#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>

#include "jpeglib.h"

extern long image_memory(int numbytes, void *data_ptr);
extern void throw_error(char *filename, char *error);

struct my_error_mgr {
	struct jpeg_error_mgr pub;
	
	jmp_buf setjmp_buffer;
};

typedef struct my_error_mgr *my_error_ptr;

static void
my_error_exit (j_common_ptr cinfo)
{
	my_error_ptr myerr = (my_error_ptr) cinfo->err;
//	(*cinfo->err->output_message) (cinfo);
	
	longjmp(myerr->setjmp_buffer, 1);
}

long
load_jpeg(char *filename, int *width, int *height)
{
	struct jpeg_decompress_struct cinfo;
	struct my_error_mgr jerr;
	
	FILE *jpeg_file = fopen(filename, "rb");
	
	if(!jpeg_file)
		throw_error(filename, "File can't be opened.");
	
	cinfo.err = jpeg_std_error(&jerr.pub);
	jerr.pub.error_exit = my_error_exit;
	if (setjmp(jerr.setjmp_buffer)) {
		jpeg_destroy_decompress(&cinfo);
		fclose(jpeg_file);
		throw_error(filename, "JPEG Error.");
	}
	
	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo, jpeg_file);
	jpeg_read_header(&cinfo, 1);
	jpeg_start_decompress(&cinfo);
	
	(*width) = cinfo.output_width;
	(*height) = cinfo.output_height;
	int components = cinfo.output_components;
	if(components != 3)
		throw_error(filename, "JPEG Error: File is not an RGB JPEG file.");
	
	int rowbytes = (*width)*components;
	JSAMPLE *pixels;
	long ruby_value = image_memory(rowbytes*(*height), &pixels);
//	volatile VALUE data = rb_str_new(NULL, 0);
//	rb_str_resize(data, rowbytes*(*height));
	
//	JSAMPLE *pixels = (JSAMPLE *)StringValuePtr(data);
	JSAMPROW row = pixels + ((*height) - 1)*rowbytes;
	
	while (cinfo.output_scanline < *height) {
		jpeg_read_scanlines(&cinfo, &row, 1);
		row -= rowbytes;
	}
	
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);
	fclose(jpeg_file);
	
	return ruby_value;
}
